home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ddj0492.zip / DFLAT.492 < prev    next >
Text File  |  1992-03-18  |  29KB  |  960 lines

  1. _C PROGRAMMING COLUMN_
  2. by Al Stevens
  3.  
  4. [LISTING ONE]
  5.  
  6.  
  7. /* ---------------- menubar.c ------------------ */
  8.  
  9. #include "dflat.h"
  10.  
  11. static void reset_menubar(WINDOW);
  12.  
  13. static struct {
  14.     int x1, x2;     /* position in menu bar */
  15.     char sc;        /* shortcut key value   */
  16. } menu[10];
  17. static int mctr;
  18.  
  19. MBAR *ActiveMenuBar;
  20. static MENU *ActiveMenu;
  21.  
  22. static WINDOW mwnd;
  23. static BOOL Selecting;
  24.  
  25. static WINDOW Cascaders[MAXCASCADES];
  26. static int casc;
  27. static WINDOW GetDocFocus(WINDOW);
  28.  
  29. /* ----------- SETFOCUS Message ----------- */
  30. static void SetFocusMsg(WINDOW wnd, PARAM p1)
  31. {
  32.     if ((int)p1 && ActiveMenuBar->ActiveSelection == -1)
  33.         ActiveMenuBar->ActiveSelection = 0;
  34.     SendMessage(wnd, PAINT, 0, 0);
  35.     if (!(int)p1) 
  36.         SendMessage(GetParent(wnd), ADDSTATUS, 0, 0);
  37. }
  38.  
  39. /* --------- BUILDMENU Message --------- */
  40. static void BuildMenuMsg(WINDOW wnd, PARAM p1)
  41. {
  42.     int offset = 3;
  43.     reset_menubar(wnd);
  44.     mctr = 0;
  45.     ActiveMenuBar = (MBAR *) p1;
  46.     ActiveMenu = ActiveMenuBar->PullDown;
  47.     while (ActiveMenu->Title != NULL &&
  48.             ActiveMenu->Title != (void*)-1)    {
  49.         char *cp;
  50.         if (strlen(GetText(wnd)+offset) <
  51.                 strlen(ActiveMenu->Title)+3)
  52.             break;
  53.         GetText(wnd) = realloc(GetText(wnd),
  54.             strlen(GetText(wnd))+5);
  55.         memmove(GetText(wnd) + offset+4, GetText(wnd) + offset,
  56.                 strlen(GetText(wnd))-offset+1);
  57.         CopyCommand(GetText(wnd)+offset,ActiveMenu->Title,FALSE,
  58.                 wnd->WindowColors [STD_COLOR] [BG]);
  59.         menu[mctr].x1 = offset;
  60.         offset += strlen(ActiveMenu->Title) + (3+MSPACE);
  61.         menu[mctr].x2 = offset-MSPACE;
  62.         cp = strchr(ActiveMenu->Title, SHORTCUTCHAR);
  63.         if (cp)
  64.             menu[mctr].sc = tolower(*(cp+1));
  65.         mctr++;
  66.         ActiveMenu++;
  67.     }
  68.     ActiveMenu = ActiveMenuBar->PullDown;
  69. }
  70.  
  71. /* ---------- PAINT Message ---------- */
  72. static void PaintMsg(WINDOW wnd)
  73. {
  74.     if (wnd == inFocus)
  75.         SendMessage(GetParent(wnd), ADDSTATUS, 0, 0);
  76.     SetStandardColor(wnd);
  77.     wputs(wnd, GetText(wnd), 0, 0);
  78.     if (ActiveMenuBar->ActiveSelection != -1 &&
  79.             (wnd == inFocus || mwnd != NULL))    {
  80.         char *sel;
  81.         char *cp;
  82.         if ((sel = malloc(200)) != NULL)    {
  83.             int offset=menu[ActiveMenuBar->ActiveSelection].x1;
  84.             int offset1=menu[ActiveMenuBar->ActiveSelection].x2;
  85.             GetText(wnd)[offset1] = '\0';
  86.             SetReverseColor(wnd);
  87.             memset(sel, '\0', 200);
  88.             strcpy(sel, GetText(wnd)+offset);
  89.             cp = strchr(sel, CHANGECOLOR);
  90.             if (cp != NULL)
  91.                 *(cp + 2) = background | 0x80;
  92.             wputs(wnd, sel,
  93.                 offset-ActiveMenuBar->ActiveSelection*4, 0);
  94.             GetText(wnd)[offset1] = ' ';
  95.             if (!Selecting && mwnd == NULL && wnd == inFocus) {
  96.                 char *st = ActiveMenu
  97.                     [ActiveMenuBar->ActiveSelection].StatusText;
  98.                 if (st != NULL)
  99.                     SendMessage(GetParent(wnd), ADDSTATUS,
  100.                         (PARAM)st, 0);
  101.             }
  102.             free(sel);
  103.         }
  104.     }
  105. }
  106.  
  107. /* ------------ KEYBOARD Message ------------- */
  108. static void KeyboardMsg(WINDOW wnd, PARAM p1)
  109. {
  110.     MENU *mnu;
  111.     if (mwnd == NULL)    {
  112.         /* ----- search for menu bar shortcut keys ---- */
  113.         int c = tolower((int)p1);
  114.         int a = AltConvert((int)p1);
  115.         int j;
  116.         for (j = 0; j < mctr; j++)    {
  117.             if ((inFocus == wnd && menu[j].sc == c) ||
  118.                     (a && menu[j].sc == a))    {
  119.                 SendMessage(wnd, MB_SELECTION, j, 0);
  120.                 return;
  121.             }
  122.         }
  123.     }
  124.     /* -------- search for accelerator keys -------- */
  125.     mnu = ActiveMenu;
  126.     while (mnu->Title != (void *)-1)    {
  127.         struct PopDown *pd = mnu->Selections;
  128.         if (mnu->PrepMenu)
  129.             (*(mnu->PrepMenu))(GetDocFocus(wnd), mnu);
  130.         while (pd->SelectionTitle != NULL)    {
  131.             if (pd->Accelerator == (int) p1)    {
  132.                 if (pd->Attrib & INACTIVE)
  133.                     beep();
  134.                 else    {
  135.                     if (pd->Attrib & TOGGLE)
  136.                         pd->Attrib ^= CHECKED;
  137.                     SendMessage(GetDocFocus(wnd),
  138.                         SETFOCUS, TRUE, 0);
  139.                     PostMessage(GetParent(wnd),
  140.                         COMMAND, pd->ActionId, 0);
  141.                 }
  142.                 return;
  143.             }
  144.             pd++;
  145.         }
  146.         mnu++;
  147.     }
  148.     switch ((int)p1)    {
  149.         case F1:
  150.             if (ActiveMenu != NULL &&
  151.                 (mwnd == NULL ||
  152.                 (ActiveMenu+ActiveMenuBar->ActiveSelection)->
  153.                     Selections[0].SelectionTitle == NULL)) {
  154.                 DisplayHelp(wnd,
  155.         (ActiveMenu+ActiveMenuBar->ActiveSelection)->Title+1);
  156.                 return;
  157.             }
  158.             break;
  159.         case '\r':
  160.             if (mwnd == NULL &&
  161.                     ActiveMenuBar->ActiveSelection != -1)
  162.                 SendMessage(wnd, MB_SELECTION,
  163.                     ActiveMenuBar->ActiveSelection, 0);
  164.             break;
  165.         case F10:
  166.             if (wnd != inFocus && mwnd == NULL)    {
  167.                 SendMessage(wnd, SETFOCUS, TRUE, 0);
  168.                 break;
  169.             }
  170.             /* ------- fall through ------- */
  171.         case ESC:
  172.             if (inFocus == wnd && mwnd == NULL)    {
  173.                 ActiveMenuBar->ActiveSelection = -1;
  174.                 SendMessage(GetDocFocus(wnd),SETFOCUS,TRUE,0);
  175.                 SendMessage(wnd, PAINT, 0, 0);
  176.             }
  177.             break;
  178.         case FWD:
  179.             ActiveMenuBar->ActiveSelection++;
  180.             if (ActiveMenuBar->ActiveSelection == mctr)
  181.                 ActiveMenuBar->ActiveSelection = 0;
  182.             if (mwnd != NULL)
  183.                 SendMessage(wnd, MB_SELECTION,
  184.                     ActiveMenuBar->ActiveSelection, 0);
  185.             else 
  186.                 SendMessage(wnd, PAINT, 0, 0);
  187.             break;
  188.         case BS:
  189.             if (ActiveMenuBar->ActiveSelection == 0)
  190.                 ActiveMenuBar->ActiveSelection = mctr;
  191.             --ActiveMenuBar->ActiveSelection;
  192.             if (mwnd != NULL)
  193.                 SendMessage(wnd, MB_SELECTION,
  194.                     ActiveMenuBar->ActiveSelection, 0);
  195.             else 
  196.                 SendMessage(wnd, PAINT, 0, 0);
  197.             break;
  198.         default:
  199.             break;
  200.     }
  201. }
  202.  
  203. /* --------------- LEFT_BUTTON Message ---------- */
  204. static void LeftButtonMsg(WINDOW wnd, PARAM p1)
  205. {
  206.     int i;
  207.     int mx = (int) p1 - GetLeft(wnd);
  208.     /* --- compute the selection that the left button hit --- */
  209.     for (i = 0; i < mctr; i++)
  210.         if (mx >= menu[i].x1-4*i &&
  211.                 mx <= menu[i].x2-4*i-5)
  212.             break;
  213.     if (i < mctr)
  214.         if (i != ActiveMenuBar->ActiveSelection || mwnd == NULL)
  215.             SendMessage(wnd, MB_SELECTION, i, 0);
  216. }
  217.  
  218. /* -------------- MB_SELECTION Message -------------- */
  219. static void SelectionMsg(WINDOW wnd, PARAM p1, PARAM p2)
  220. {
  221.     int wd, mx, my;
  222.     MENU *mnu;
  223.  
  224.     Selecting = TRUE;
  225.     mnu = ActiveMenu+(int)p1;
  226.     if (mnu->PrepMenu != NULL)
  227.         (*(mnu->PrepMenu))(GetDocFocus(wnd), mnu);
  228.     wd = MenuWidth(mnu->Selections);
  229.     if (p2)    {
  230.         mx = GetLeft(inFocus) + WindowWidth(inFocus) - 1;
  231.         my = GetTop(inFocus) + inFocus->selection;
  232.     }
  233.     else    {
  234.         int offset = menu[(int)p1].x1 - 4 * (int)p1;
  235.         if (mwnd != NULL)    {
  236.             SendMessage(wnd, SETFOCUS, TRUE, 0);
  237.             SendMessage(mwnd, CLOSE_WINDOW, 0, 0);
  238.         }
  239.         ActiveMenuBar->ActiveSelection = (int) p1;
  240.         if (offset > WindowWidth(wnd)-wd)
  241.             offset = WindowWidth(wnd)-wd;
  242.         mx = GetLeft(wnd)+offset;
  243.         my = GetTop(wnd)+1;
  244.     }
  245.     mwnd = CreateWindow(POPDOWNMENU, NULL,
  246.                 mx, my,
  247.                 MenuHeight(mnu->Selections),
  248.                 wd,
  249.                 NULL,
  250.                 wnd,
  251.                 NULL,
  252.                 0);
  253.     AddAttribute(mwnd, SHADOW);
  254.     if (mnu->Selections[0].SelectionTitle != NULL)    {
  255.         SendMessage(mwnd, BUILD_SELECTIONS, (PARAM) mnu, 0);
  256.         SendMessage(mwnd, SETFOCUS, TRUE, 0);
  257.     }
  258.     else
  259.         SendMessage(wnd, PAINT, 0, 0);
  260.     Selecting = FALSE;
  261. }
  262.  
  263. /* --------- COMMAND Message ---------- */
  264. static void CommandMsg(WINDOW wnd, PARAM p1, PARAM p2)
  265. {
  266.     if (isCascadedCommand(ActiveMenuBar, (int)p1))    {
  267.         /* find the cascaded menu based on command id in p1 */
  268.         MENU *mnu = ActiveMenu+mctr;
  269.         while (mnu->Title != (void *)-1)    {
  270.             if (mnu->CascadeId == (int) p1)    {
  271.                 if (casc < MAXCASCADES)    {
  272.                     Cascaders[casc++] = mwnd;
  273.                     SendMessage(wnd, MB_SELECTION,
  274.                         (PARAM)(mnu-ActiveMenu), TRUE);
  275.                 }
  276.                 break;
  277.             }
  278.             mnu++;
  279.         }
  280.     }
  281.     else     {
  282.         if (mwnd != NULL)
  283.             SendMessage(mwnd, CLOSE_WINDOW, 0, 0);
  284.         SendMessage(GetDocFocus(wnd), SETFOCUS, TRUE, 0);
  285.         PostMessage(GetParent(wnd), COMMAND, p1, p2);
  286.     }
  287. }
  288.  
  289. /* --------------- CLOSE_POPDOWN Message --------------- */
  290. static void ClosePopdownMsg(WINDOW wnd)
  291. {
  292.     if (casc > 0)
  293.         SendMessage(Cascaders[--casc], CLOSE_WINDOW, 0, 0);
  294.     else     {
  295.         mwnd = NULL;
  296.         ActiveMenuBar->ActiveSelection = -1;
  297.         if (!Selecting)
  298.             SendMessage(GetDocFocus(wnd), SETFOCUS, TRUE, 0);
  299.         SendMessage(wnd, PAINT, 0, 0);
  300.     }
  301. }
  302.  
  303. /* ---------------- CLOSE_WINDOW Message --------------- */
  304. static void CloseWindowMsg(WINDOW wnd)
  305. {
  306.     if (GetText(wnd) != NULL)    {
  307.         free(GetText(wnd));
  308.         GetText(wnd) = NULL;
  309.     }
  310.     mctr = 0;
  311.     ActiveMenuBar->ActiveSelection = -1;
  312.     ActiveMenu = NULL;
  313.     ActiveMenuBar = NULL;
  314. }
  315.  
  316. /* --- Window processing module for MENUBAR window class --- */
  317. int MenuBarProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  318. {
  319.     int rtn;
  320.  
  321.     switch (msg)    {
  322.         case CREATE_WINDOW:
  323.             reset_menubar(wnd);
  324.             break;
  325.         case SETFOCUS:
  326.             rtn = BaseWndProc(MENUBAR, wnd, msg, p1, p2);
  327.             SetFocusMsg(wnd, p1);
  328.             return rtn;
  329.         case BUILDMENU:
  330.             BuildMenuMsg(wnd, p1);
  331.             break;
  332.         case PAINT:    
  333.             if (!isVisible(wnd) || GetText(wnd) == NULL)
  334.                 break;
  335.             PaintMsg(wnd);
  336.             return FALSE;
  337.         case BORDER:
  338.             return TRUE;
  339.         case KEYBOARD:
  340.             KeyboardMsg(wnd, p1);
  341.             return TRUE;
  342.         case LEFT_BUTTON:
  343.             LeftButtonMsg(wnd, p1);
  344.             return TRUE;
  345.         case MB_SELECTION:
  346.             SelectionMsg(wnd, p1, p2);
  347.             break;
  348.         case COMMAND:
  349.             CommandMsg(wnd, p1, p2);
  350.             return TRUE;
  351.         case INSIDE_WINDOW:
  352.             return InsideRect(p1, p2, WindowRect(wnd));
  353.         case CLOSE_POPDOWN:
  354.             ClosePopdownMsg(wnd);
  355.             return TRUE;
  356.         case CLOSE_WINDOW:
  357.             rtn = BaseWndProc(MENUBAR, wnd, msg, p1, p2);
  358.             CloseWindowMsg(wnd);
  359.             return rtn;
  360.         default:
  361.             break;
  362.     }
  363.     return BaseWndProc(MENUBAR, wnd, msg, p1, p2);
  364. }
  365.  
  366. /* ----- return the WINDOW handle of the document window
  367.      that had the focus when the MENUBAR was activated ----- */
  368. static WINDOW GetDocFocus(WINDOW wnd)
  369. {
  370.     WINDOW DocFocus = Focus.LastWindow;
  371.     CLASS cl;
  372.     while ((cl = GetClass(DocFocus)) == MENUBAR ||
  373.                 cl == POPDOWNMENU ||
  374.                     cl == STATUSBAR ||
  375.                         cl == APPLICATION)                    {
  376.         if ((DocFocus = PrevWindow(DocFocus)) == NULL)    {
  377.             DocFocus = GetParent(wnd);
  378.             break;
  379.         }
  380.     }
  381.     return DocFocus;
  382. }
  383.  
  384. /* ------------- reset the MENUBAR -------------- */
  385. static void reset_menubar(WINDOW wnd)
  386. {
  387.     if ((GetText(wnd) =
  388.             realloc(GetText(wnd), SCREENWIDTH+5)) != NULL)    {
  389.         memset(GetText(wnd), ' ', SCREENWIDTH);
  390.         *(GetText(wnd)+WindowWidth(wnd)) = '\0';
  391.     }
  392. }
  393.  
  394.  
  395. [LISTING TWO]
  396.  
  397. /* ------------- popdown.c ----------- */
  398.  
  399. #include "dflat.h"
  400.  
  401. static int SelectionWidth(struct PopDown *);
  402. static int py = -1;
  403.  
  404. /* ------------ CREATE_WINDOW Message ------------- */
  405. static int CreateWindowMsg(WINDOW wnd)
  406. {
  407.     int rtn;
  408.     ClearAttribute(wnd, HASTITLEBAR     |
  409.                         VSCROLLBAR     |
  410.                         MOVEABLE     |
  411.                         SIZEABLE     |
  412.                         HSCROLLBAR);
  413.     rtn = BaseWndProc(POPDOWNMENU, wnd, CREATE_WINDOW, 0, 0);
  414.     SendMessage(wnd, CAPTURE_MOUSE, 0, 0);
  415.     SendMessage(wnd, CAPTURE_KEYBOARD, 0, 0);
  416.     SendMessage(NULL, SAVE_CURSOR, 0, 0);
  417.     SendMessage(NULL, HIDE_CURSOR, 0, 0);
  418.     return rtn;
  419. }
  420.  
  421. /* --------- LEFT_BUTTON Message --------- */
  422. static void LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  423. {
  424.     int my = (int) p2 - GetTop(wnd);
  425.     if (InsideRect(p1, p2, ClientRect(wnd)))    {
  426.         if (my != py)    {
  427.             SendMessage(wnd, LB_SELECTION,
  428.                     (PARAM) wnd->wtop+my-1, TRUE);
  429.             py = my;
  430.         }
  431.     }
  432.     else if ((int)p2 == GetTop(GetParent(wnd)))
  433.         if (GetClass(GetParent(wnd)) == MENUBAR)
  434.             PostMessage(GetParent(wnd), LEFT_BUTTON, p1, p2);
  435. }
  436.  
  437. /* -------- BUTTON_RELEASED Message -------- */
  438. static BOOL ButtonReleasedMsg(WINDOW wnd, PARAM p1, PARAM p2)
  439. {
  440.     py = -1;
  441.     if (InsideRect((int)p1, (int)p2, ClientRect(wnd)))    {
  442.         int sel = (int)p2 - GetClientTop(wnd);
  443.         if (*TextLine(wnd, sel) != LINE)
  444.             SendMessage(wnd, LB_CHOOSE, wnd->selection, 0);
  445.     }
  446.     else    {
  447.         WINDOW pwnd = GetParent(wnd);
  448.         if (GetClass(pwnd) == MENUBAR && (int)p2==GetTop(pwnd))
  449.             return FALSE;
  450.         if ((int)p1 == GetLeft(pwnd)+2)
  451.             return FALSE;
  452.         SendMessage(wnd, CLOSE_WINDOW, 0, 0);
  453.         return TRUE;
  454.     }
  455.     return FALSE;
  456. }
  457.  
  458. /* --------- PAINT Message -------- */
  459. static void PaintMsg(WINDOW wnd)
  460. {
  461.     int wd;
  462.     unsigned char sep[80], *cp = sep;
  463.     unsigned char sel[80];
  464.     struct PopDown *ActivePopDown;
  465.     struct PopDown *pd1;
  466.  
  467.     ActivePopDown = pd1 = wnd->mnu->Selections;
  468.     wd = MenuWidth(ActivePopDown)-2;
  469.     while (wd--)
  470.         *cp++ = LINE;
  471.     *cp = '\0';
  472.     SendMessage(wnd, CLEARTEXT, 0, 0);
  473.     wnd->selection = wnd->mnu->Selection;
  474.     while (pd1->SelectionTitle != NULL)    {
  475.         if (*pd1->SelectionTitle == LINE)
  476.             SendMessage(wnd, ADDTEXT, (PARAM) sep, 0);
  477.         else    {
  478.             int len;
  479.             memset(sel, '\0', sizeof sel);
  480.             if (pd1->Attrib & INACTIVE)
  481.                 /* ------ inactive menu selection ----- */
  482.                 sprintf(sel, "%c%c%c",
  483.                     CHANGECOLOR,
  484.                     wnd->WindowColors [HILITE_COLOR] [FG]|0x80,
  485.                     wnd->WindowColors [STD_COLOR] [BG]|0x80);
  486.             strcat(sel, " ");
  487.             if (pd1->Attrib & CHECKED)
  488.                 /* ---- paint the toggle checkmark ---- */
  489.                 sel[strlen(sel)-1] = CHECKMARK;
  490.             len=CopyCommand(sel+strlen(sel),pd1->SelectionTitle,
  491.                     pd1->Attrib & INACTIVE,
  492.                     wnd->WindowColors [STD_COLOR] [BG]);
  493.             if (pd1->Accelerator)    {
  494.                 /* ---- paint accelerator key ---- */
  495.                 int i;
  496.                 int wd1 = 2+SelectionWidth(ActivePopDown) -
  497.                                     strlen(pd1->SelectionTitle);
  498.                 for (i = 0; keys[i].keylabel; i++)    {
  499.                     if (keys[i].keycode == pd1->Accelerator)   {
  500.                         while (wd1--)
  501.                             strcat(sel, " ");
  502.                         sprintf(sel+strlen(sel), "[%s]",
  503.                             keys[i].keylabel);
  504.                         break;
  505.                     }
  506.                 }
  507.             }
  508.             if (pd1->Attrib & CASCADED)    {
  509.                 /* ---- paint cascaded menu token ---- */
  510.                 if (!pd1->Accelerator)    {
  511.                     wd = MenuWidth(ActivePopDown)-len+1;
  512.                     while (wd--)
  513.                         strcat(sel, " ");
  514.                 }
  515.                 sel[strlen(sel)-1] = CASCADEPOINTER;
  516.             }
  517.             else
  518.                 strcat(sel, " ");
  519.             strcat(sel, " ");
  520.             sel[strlen(sel)-1] = RESETCOLOR;
  521.             SendMessage(wnd, ADDTEXT, (PARAM) sel, 0);
  522.         }
  523.         pd1++;
  524.     }
  525. }
  526.  
  527. /* ---------- BORDER Message ----------- */
  528. static int BorderMsg(WINDOW wnd)
  529. {
  530.     int i, rtn = TRUE;
  531.     WINDOW currFocus;
  532.     if (wnd->mnu != NULL)    {
  533.         currFocus = inFocus;
  534.         inFocus = NULL;
  535.         rtn = BaseWndProc(POPDOWNMENU, wnd, BORDER, 0, 0);
  536.         inFocus = currFocus;
  537.         for (i = 0; i < ClientHeight(wnd); i++)    {
  538.             if (*TextLine(wnd, i) == LINE)    {
  539.                 wputch(wnd, LEDGE, 0, i+1);
  540.                 wputch(wnd, REDGE, WindowWidth(wnd)-1, i+1);
  541.             }
  542.         }
  543.     }
  544.     return rtn;
  545. }
  546.  
  547. /* -------------- LB_CHOOSE Message -------------- */
  548. static void LBChooseMsg(WINDOW wnd, PARAM p1)
  549. {
  550.     struct PopDown *ActivePopDown = wnd->mnu->Selections;
  551.     if (ActivePopDown != NULL)    {
  552.         int *attr = &(ActivePopDown+(int)p1)->Attrib;
  553.         wnd->mnu->Selection = (int)p1;
  554.         if (!(*attr & INACTIVE))    {
  555.             if (*attr & TOGGLE)
  556.                 *attr ^= CHECKED;
  557.             PostMessage(GetParent(wnd), COMMAND,
  558.                 (ActivePopDown+(int)p1)->ActionId, p1);
  559.         }
  560.         else
  561.             beep();
  562.     }
  563. }
  564.  
  565. /* ---------- KEYBOARD Message --------- */
  566. static BOOL KeyboardMsg(WINDOW wnd, PARAM p1, PARAM p2)
  567. {
  568.     struct PopDown *ActivePopDown = wnd->mnu->Selections;
  569.     if (wnd->mnu != NULL)    {
  570.         if (ActivePopDown != NULL)    {
  571.             int c = (int)p1;
  572.             int sel = 0;
  573.             int a;
  574.             struct PopDown *pd = ActivePopDown;
  575.  
  576.             if ((c & OFFSET) == 0)
  577.                 c = tolower(c);
  578.             a = AltConvert(c);
  579.  
  580.             while (pd->SelectionTitle != NULL)    {
  581.                 char *cp = strchr(pd->SelectionTitle,
  582.                                 SHORTCUTCHAR);
  583.                 int sc = tolower(*(cp+1));
  584.                 if ((cp && sc == c) ||
  585.                         (a && sc == a) ||
  586.                             pd->Accelerator == c)    {
  587.                     PostMessage(wnd, LB_SELECTION, sel, 0);
  588.                     PostMessage(wnd, LB_CHOOSE, sel, TRUE);
  589.                     return TRUE;
  590.                 }
  591.                 pd++, sel++;
  592.             }
  593.         }
  594.     }
  595.     switch ((int)p1)    {
  596.         case F1:
  597.             if (ActivePopDown == NULL)
  598.                 SendMessage(GetParent(wnd), KEYBOARD, p1, p2);
  599.             else 
  600.                 DisplayHelp(wnd,
  601.                     (ActivePopDown+wnd->selection)->help);
  602.             return TRUE;
  603.         case ESC:
  604.             SendMessage(wnd, CLOSE_WINDOW, 0, 0);
  605.             return TRUE;
  606.         case FWD:
  607.         case BS:
  608.             if (GetClass(GetParent(wnd)) == MENUBAR)
  609.                 PostMessage(GetParent(wnd), KEYBOARD, p1, p2);
  610.             return TRUE;
  611.         case UP:
  612.             if (wnd->selection == 0)    {
  613.                 if (wnd->wlines == ClientHeight(wnd))    {
  614.                     PostMessage(wnd, LB_SELECTION,
  615.                                     wnd->wlines-1, FALSE);
  616.                     return TRUE;
  617.                 }
  618.             }
  619.             break;
  620.         case DN:
  621.             if (wnd->selection == wnd->wlines-1)    {
  622.                 if (wnd->wlines == ClientHeight(wnd))    {
  623.                     PostMessage(wnd, LB_SELECTION, 0, FALSE);
  624.                     return TRUE;
  625.                 }
  626.             }
  627.             break;
  628.         case HOME:
  629.         case END:
  630.         case '\r':
  631.             break;
  632.         default:
  633.             return TRUE;
  634.     }
  635.     return FALSE;
  636. }
  637.  
  638. /* ----------- CLOSE_WINDOW Message ---------- */
  639. static int CloseWindowMsg(WINDOW wnd)
  640. {
  641.     int rtn;
  642.     SendMessage(wnd, RELEASE_MOUSE, 0, 0);
  643.     SendMessage(wnd, RELEASE_KEYBOARD, 0, 0);
  644.     SendMessage(NULL, RESTORE_CURSOR, 0, 0);
  645.     rtn = BaseWndProc(POPDOWNMENU, wnd, CLOSE_WINDOW, 0, 0);
  646.     SendMessage(GetParent(wnd), CLOSE_POPDOWN, 0, 0);
  647.     return rtn;
  648. }
  649.  
  650. /* - Window processing module for POPDOWNMENU window class - */
  651. int PopDownProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  652. {
  653.     switch (msg)    {
  654.         case CREATE_WINDOW:
  655.             return CreateWindowMsg(wnd);
  656.         case LEFT_BUTTON:
  657.             LeftButtonMsg(wnd, p1, p2);
  658.             return FALSE;
  659.         case DOUBLE_CLICK:
  660.             return TRUE;
  661.         case LB_SELECTION:
  662.             if (*TextLine(wnd, (int)p1) == LINE)
  663.                 return TRUE;
  664.             wnd->mnu->Selection = (int)p1;
  665.             break;
  666.         case BUTTON_RELEASED:
  667.             if (ButtonReleasedMsg(wnd, p1, p2))
  668.                 return TRUE;
  669.             break;
  670.         case BUILD_SELECTIONS:
  671.             wnd->mnu = (void *) p1;
  672.             wnd->selection = wnd->mnu->Selection;
  673.             break;
  674.         case PAINT:
  675.             if (wnd->mnu == NULL)
  676.                 return TRUE;
  677.             PaintMsg(wnd);
  678.             break;
  679.         case BORDER:
  680.             return BorderMsg(wnd);
  681.         case LB_CHOOSE:
  682.             LBChooseMsg(wnd, p1);
  683.             return TRUE;
  684.         case KEYBOARD:
  685.             if (KeyboardMsg(wnd, p1, p2))
  686.                 return TRUE;
  687.             break;
  688.         case CLOSE_WINDOW:
  689.             return CloseWindowMsg(wnd);
  690.         default:
  691.             break;
  692.     }
  693.     return BaseWndProc(POPDOWNMENU, wnd, msg, p1, p2);
  694. }
  695.  
  696. /* --------- compute menu height -------- */
  697. int MenuHeight(struct PopDown *pd)
  698. {
  699.     int ht = 0;
  700.     while (pd[ht].SelectionTitle != NULL)
  701.         ht++;
  702.     return ht+2;
  703. }
  704.  
  705. /* --------- compute menu width -------- */
  706. int MenuWidth(struct PopDown *pd)
  707. {
  708.     int wd = 0, i;
  709.     int len = 0;
  710.  
  711.     wd = SelectionWidth(pd);
  712.     while (pd->SelectionTitle != NULL)    {
  713.         if (pd->Accelerator)    {
  714.             for (i = 0; keys[i].keylabel; i++)
  715.                 if (keys[i].keycode == pd->Accelerator)    {
  716.                     len = max(len, 2+strlen(keys[i].keylabel));
  717.                     break;
  718.                 }
  719.         }
  720.         if (pd->Attrib & CASCADED)
  721.             len = max(len, 2);
  722.         pd++;
  723.     }
  724.     return wd+5+len;
  725. }
  726.  
  727. /* ---- compute the maximum selection width in a menu ---- */
  728. static int SelectionWidth(struct PopDown *pd)
  729. {
  730.     int wd = 0;
  731.     while (pd->SelectionTitle != NULL)    {
  732.         int len = strlen(pd->SelectionTitle)-1;
  733.         wd = max(wd, len);
  734.         pd++;
  735.     }
  736.     return wd;
  737. }
  738.  
  739. /* ----- copy a menu command to a display buffer ---- */
  740. int CopyCommand(unsigned char *dest, unsigned char *src,
  741.                                         int skipcolor, int bg)
  742. {
  743.     unsigned char *d = dest;
  744.     while (*src && *src != '\n')    {
  745.         if (*src == SHORTCUTCHAR)    {
  746.             src++;
  747.             if (!skipcolor)    {
  748.                 *dest++ = CHANGECOLOR;
  749.                 *dest++ = cfg.clr[POPDOWNMENU]
  750.                             [HILITE_COLOR] [BG] | 0x80;
  751.                 *dest++ = bg | 0x80;
  752.                 *dest++ = *src++;
  753.                 *dest++ = RESETCOLOR;
  754.             }
  755.         }
  756.         else
  757.             *dest++ = *src++;
  758.     }
  759.     return (int) (dest - d);
  760. }
  761.  
  762.  
  763.  
  764. [LISTING THREE]
  765.  
  766. /* ------------- menu.c ------------- */
  767.  
  768. #include "dflat.h"
  769.  
  770. static struct PopDown *FindCmd(MBAR *mn, int cmd)
  771. {
  772.     MENU *mnu = mn->PullDown;
  773.     while (mnu->Title != (void *)-1)    {
  774.         struct PopDown *pd = mnu->Selections;
  775.         while (pd->SelectionTitle != NULL)    {
  776.             if (pd->ActionId == cmd)
  777.                 return pd;
  778.             pd++;
  779.         }
  780.         mnu++;
  781.     }
  782.     return NULL;
  783. }
  784.  
  785. char *GetCommandText(MBAR *mn, int cmd)
  786. {
  787.     struct PopDown *pd = FindCmd(mn, cmd);
  788.     if (pd != NULL)
  789.         return pd->SelectionTitle;
  790.     return NULL;
  791. }
  792.  
  793. BOOL isCascadedCommand(MBAR *mn, int cmd)
  794. {
  795.     struct PopDown *pd = FindCmd(mn, cmd);
  796.     if (pd != NULL)
  797.         return pd->Attrib & CASCADED;
  798.     return FALSE;
  799. }
  800.  
  801. void ActivateCommand(MBAR *mn, int cmd)
  802. {
  803.     struct PopDown *pd = FindCmd(mn, cmd);
  804.     if (pd != NULL)
  805.         pd->Attrib &= ~INACTIVE;
  806. }
  807.  
  808. void DeactivateCommand(MBAR *mn, int cmd)
  809. {
  810.     struct PopDown *pd = FindCmd(mn, cmd);
  811.     if (pd != NULL)
  812.         pd->Attrib |= INACTIVE;
  813. }
  814.  
  815. BOOL isActive(MBAR *mn, int cmd)
  816. {
  817.     struct PopDown *pd = FindCmd(mn, cmd);
  818.     if (pd != NULL)
  819.         return !(pd->Attrib & INACTIVE);
  820.     return FALSE;
  821. }
  822.  
  823. BOOL GetCommandToggle(MBAR *mn, int cmd)
  824. {
  825.     struct PopDown *pd = FindCmd(mn, cmd);
  826.     if (pd != NULL)
  827.         return (pd->Attrib & CHECKED) != 0;
  828.     return FALSE;
  829. }
  830.  
  831. void SetCommandToggle(MBAR *mn, int cmd)
  832. {
  833.     struct PopDown *pd = FindCmd(mn, cmd);
  834.     if (pd != NULL)
  835.         pd->Attrib |= CHECKED;
  836. }
  837.  
  838. void ClearCommandToggle(MBAR *mn, int cmd)
  839. {
  840.     struct PopDown *pd = FindCmd(mn, cmd);
  841.     if (pd != NULL)
  842.         pd->Attrib &= ~CHECKED;
  843. }
  844.  
  845. void InvertCommandToggle(MBAR *mn, int cmd)
  846. {
  847.     struct PopDown *pd = FindCmd(mn, cmd);
  848.     if (pd != NULL)
  849.         pd->Attrib ^= CHECKED;
  850. }
  851.  
  852.  
  853. [LISTING FOUR]
  854.  
  855.  
  856. /* ------------- sysmenu.c ------------ */
  857.  
  858. #include "dflat.h"
  859.  
  860. int SystemMenuProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  861. {
  862.     int mx, my;
  863.     WINDOW wnd1;
  864.     switch (msg)    {
  865.         case CREATE_WINDOW:
  866.             wnd->holdmenu = ActiveMenuBar;
  867.             ActiveMenuBar = &SystemMenu;
  868.             SystemMenu.PullDown[0].Selection = 0;
  869.             break;
  870.         case LEFT_BUTTON:
  871.             wnd1 = GetParent(wnd);
  872.             mx = (int) p1 - GetLeft(wnd1);
  873.             my = (int) p2 - GetTop(wnd1);
  874.             if (HitControlBox(wnd1, mx, my))
  875.                 return TRUE;
  876.             break;
  877.         case LB_CHOOSE:
  878.             PostMessage(wnd, CLOSE_WINDOW, 0, 0);
  879.             break;
  880.         case DOUBLE_CLICK:
  881.             if (p2 == GetTop(GetParent(wnd)))    {
  882.                 PostMessage(GetParent(wnd), msg, p1, p2);
  883.                 SendMessage(wnd, CLOSE_WINDOW, TRUE, 0);
  884.             }
  885.             return TRUE;
  886.         case SHIFT_CHANGED:
  887.             return TRUE;
  888.         case CLOSE_WINDOW:
  889.             ActiveMenuBar = wnd->holdmenu;
  890.             break;
  891.         default:
  892.             break;
  893.     }
  894.     return DefaultWndProc(wnd, msg, p1, p2);
  895. }
  896.  
  897. /* ------- Build a system menu -------- */
  898. void BuildSystemMenu(WINDOW wnd)
  899. {
  900.     int lf = GetLeft(wnd)+1;
  901.     int tp = GetTop(wnd)+1;
  902.     int ht = MenuHeight(SystemMenu.PullDown[0].Selections);
  903.     int wd = MenuWidth(SystemMenu.PullDown[0].Selections);
  904.     WINDOW SystemMenuWnd;
  905.  
  906.     SystemMenu.PullDown[0].Selections[6].Accelerator = 
  907.         (GetClass(wnd) == APPLICATION) ? ALT_F4 : CTRL_F4;
  908.  
  909.     if (lf+wd > SCREENWIDTH-1)
  910.         lf = (SCREENWIDTH-1) - wd;
  911.     if (tp+ht > SCREENHEIGHT-2)
  912.         tp = (SCREENHEIGHT-2) - ht;
  913.  
  914.     SystemMenuWnd = CreateWindow(POPDOWNMENU, NULL,
  915.                 lf,tp,ht,wd,NULL,wnd,SystemMenuProc, 0);
  916.  
  917. #ifdef INCLUDE_RESTORE
  918.     if (wnd->condition == ISRESTORED)
  919.         DeactivateCommand(&SystemMenu, ID_SYSRESTORE);
  920.     else
  921.         ActivateCommand(&SystemMenu, ID_SYSRESTORE);
  922. #endif
  923.  
  924.     if (TestAttribute(wnd, MOVEABLE)
  925. #ifdef INCLUDE_MAXIMIZE
  926.             && wnd->condition != ISMAXIMIZED
  927. #endif
  928.                 )
  929.         ActivateCommand(&SystemMenu, ID_SYSMOVE);
  930.     else
  931.         DeactivateCommand(&SystemMenu, ID_SYSMOVE);
  932.  
  933.     if (wnd->condition != ISRESTORED ||
  934.             TestAttribute(wnd, SIZEABLE) == FALSE)
  935.         DeactivateCommand(&SystemMenu, ID_SYSSIZE);
  936.     else
  937.         ActivateCommand(&SystemMenu, ID_SYSSIZE);
  938.  
  939. #ifdef INCLUDE_MINIMIZE
  940.     if (wnd->condition == ISMINIMIZED ||
  941.             TestAttribute(wnd, MINMAXBOX) == FALSE)
  942.         DeactivateCommand(&SystemMenu, ID_SYSMINIMIZE);
  943.     else
  944.         ActivateCommand(&SystemMenu, ID_SYSMINIMIZE);
  945. #endif
  946.  
  947. #ifdef INCLUDE_MAXIMIZE
  948.     if (wnd->condition != ISRESTORED ||
  949.             TestAttribute(wnd, MINMAXBOX) == FALSE)
  950.         DeactivateCommand(&SystemMenu, ID_SYSMAXIMIZE);
  951.     else
  952.         ActivateCommand(&SystemMenu, ID_SYSMAXIMIZE);
  953. #endif
  954.  
  955.     SendMessage(SystemMenuWnd, BUILD_SELECTIONS,
  956.                 (PARAM) &SystemMenu.PullDown[0], 0);
  957.     SendMessage(SystemMenuWnd, SHOW_WINDOW, 0, 0);
  958. }
  959.  
  960.